/**
 * Matrix Framework 前端认证服务
 * 集成Keycloak认证和ABP vNext框架功能
 * 负责处理用户登录、Token管理和认证流程
 */

import axios from 'axios';
import { EventEmitter } from 'events';
import abpService from './abp.service';

class AuthService extends EventEmitter {
    constructor() {
        super();
        this.accessToken = null;
        this.refreshToken = null;
        this.user = null;
        this.permissions = [];
        this.roles = [];
        this.tenantInfo = null;
        this.tokenRefreshTimer = null;
        this.isRefreshing = false;
        this.refreshQueue = [];

        // 初始化配置
        this.config = {
            keycloakUrl: process.env.VUE_APP_KEYCLOAK_URL || 'http://localhost:8080',
            apiUrl: process.env.VUE_APP_API_URL || 'http://localhost:5000',
            clientId: process.env.VUE_APP_CLIENT_ID || 'matrix-frontend',
            clientSecret: process.env.VUE_APP_CLIENT_SECRET || '',
            defaultRealm: process.env.VUE_APP_DEFAULT_REALM || 'MatrixFramework',
            tokenRefreshThreshold: 5 * 60 * 1000, // 5分钟前刷新
            autoRefresh: true
        };

        // 初始化时尝试恢复会话
        this.initFromStorage();
    }

    /**
     * 初始化认证服务
     */
    async init() {
        try {
            // 首先初始化ABP服务
            await abpService.initialize();

            // 检查是否已有有效的Token
            if (this.accessToken && !this.isTokenExpired(this.accessToken)) {
                await this.validateAndRefreshToken();
            } else {
                this.clearSession();
            }

            // 设置axios拦截器
            this.setupAxiosInterceptors();

            // 同步ABP会话信息
            await this.syncWithAbpSession();

            this.emit('initialized');
            return true;
        } catch (error) {
            console.error('AuthService初始化失败:', error);
            this.emit('error', error);
            return false;
        }
    }

    /**
     * 登录（使用ROPC方式）
     * @param {Object} credentials 登录凭据
     * @param {string} credentials.username 用户名
     * @param {string} credentials.password 密码
     * @param {string} credentials.tenantId 租户ID（可选）
     * @param {boolean} credentials.rememberMe 记住登录
     */
    async login(credentials) {
        try {
            const { username, password, tenantId, rememberMe = false } = credentials;

            if (!username || !password) {
                throw new Error('用户名和密码不能为空');
            }

            // 确定目标Realm
            const realm = this.getRealmForTenant(tenantId);

            // 直接调用Keycloak Token端点
            const tokenData = await this.authenticateWithKeycloak(username, password, realm);

            // 验证Token并获取用户信息
            await this.processAuthSuccess(tokenData, rememberMe);

            // 发布登录事件
            this.emit('login', {
                user: this.user,
                tenantInfo: this.tenantInfo,
                loginTime: new Date()
            });

            return {
                success: true,
                user: this.user,
                tenantInfo: this.tenantInfo
            };
        } catch (error) {
            console.error('登录失败:', error);

            // 发布登录失败事件
            this.emit('loginFailed', {
                error: error.message,
                username: credentials.username
            });

            return {
                success: false,
                error: this.getErrorMessage(error)
            };
        }
    }

    /**
     * 使用Keycloak进行认证
     */
    async authenticateWithKeycloak(username, password, realm) {
        const tokenUrl = `${this.config.keycloakUrl}/realms/${realm}/protocol/openid-connect/token`;

        const formData = new URLSearchParams({
            grant_type: 'password',
            client_id: this.config.clientId,
            username,
            password,
            scope: 'openid profile email roles'
        });

        // 如果有客户端密钥，添加到请求中
        if (this.config.clientSecret) {
            formData.append('client_secret', this.config.clientSecret);
        }

        const response = await fetch(tokenUrl, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded',
            },
            body: formData.toString()
        });

        if (!response.ok) {
            const errorData = await response.json().catch(() => ({}));
            throw new Error(errorData.error_description || errorData.error || '登录失败');
        }

        return await response.json();
    }

    /**
     * 处理认证成功
     */
    async processAuthSuccess(tokenData, rememberMe = false) {
        this.accessToken = tokenData.access_token;
        this.refreshToken = tokenData.refresh_token;

        // 解析JWT Token获取用户信息
        const decodedToken = this.decodeJWT(this.accessToken);

        // 获取详细的用户信息
        await this.loadUserProfile();

        // 设置Token刷新定时器
        this.setupTokenRefresh();

        // 存储到本地
        this.saveToStorage(rememberMe);

        // 设置axios默认头部
        this.updateAxiosHeaders();
    }

    /**
     * 加载用户详细信息
     */
    async loadUserProfile() {
        try {
            // 从Token解析基础信息
            const decodedToken = this.decodeJWT(this.accessToken);

            this.user = {
                id: decodedToken.sub,
                username: decodedToken.preferred_username || decodedToken.email,
                email: decodedToken.email,
                name: decodedToken.given_name || '',
                surname: decodedToken.family_name || '',
                displayName: decodedToken.name || decodedToken.preferred_username,
                tenantId: decodedToken.tenant_id,
                keycloakUserId: decodedToken.sub
            };

            // 从Token中提取角色和权限
            this.roles = decodedToken.resource_access?.[this.config.clientId]?.roles || [];
            this.permissions = decodedToken.permission ?
                (Array.isArray(decodedToken.permission) ? decodedToken.permission : [decodedToken.permission]) : [];

            // 获取详细的租户信息
            this.tenantInfo = await this.loadTenantInfo(decodedToken.tenant_id);
        } catch (error) {
            console.error('加载用户信息失败:', error);
        }
    }

    /**
     * 加载租户信息
     */
    async loadTenantInfo(tenantId) {
        if (!tenantId || tenantId === '') {
            return {
                id: null,
                name: '默认租户',
                realm: this.config.defaultRealm
            };
        }

        try {
            const response = await axios.get(`/api/tenant-management/tenants/${tenantId}`, {
                headers: this.getAuthHeaders()
            });

            return response.data;
        } catch (error) {
            console.warn('加载租户信息失败:', error);
            return {
                id: tenantId,
                name: `租户 ${tenantId.substring(0, 8)}`,
                realm: `tenant-${tenantId}`
            };
        }
    }

    /**
     * 登出
     */
    async logout() {
        try {
            // 如果有有效的Token，通知Keycloak
            if (this.accessToken && !this.isTokenExpired(this.accessToken)) {
                const decodedToken = this.decodeJWT(this.accessToken);
                const realm = this.getRealmForTenant(decodedToken.tenant_id);

                // 调用Keycloak登出端点
                const logoutUrl = `${this.config.keycloakUrl}/realms/${realm}/protocol/openid-connect/logout`;

                await fetch(logoutUrl, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/x-www-form-urlencoded',
                        'Authorization': `Bearer ${this.accessToken}`
                    },
                    body: new URLSearchParams({
                        client_id: this.config.clientId,
                        refresh_token: this.refreshToken
                    }).toString()
                });
            }

            // 清理本地数据
            await this.clearSession();

            // 发布登出事件
            this.emit('logout', {
                logoutTime: new Date(),
                user: this.user
            });

            return { success: true };
        } catch (error) {
            console.error('登出失败:', error);

            // 即使登出失败也清理本地数据
            await this.clearSession();

            return {
                success: false,
                error: this.getErrorMessage(error)
            };
        }
    }

    /**
     * 刷新Token
     */
    async refreshAccessToken() {
        if (this.isRefreshing) {
            // 如果正在刷新，等待刷新完成
            return new Promise((resolve, reject) => {
                this.refreshQueue.push({ resolve, reject });
            });
        }

        this.isRefreshing = true;

        try {
            if (!this.refreshToken) {
                throw new Error('没有刷新Token');
            }

            const decodedToken = this.decodeJWT(this.accessToken);
            const realm = this.getRealmForTenant(decodedToken.tenant_id);

            const refreshUrl = `${this.config.keycloakUrl}/realms/${realm}/protocol/openid-connect/token`;

            const formData = new URLSearchParams({
                grant_type: 'refresh_token',
                client_id: this.config.clientId,
                refresh_token: this.refreshToken,
                scope: 'openid profile email roles'
            });

            if (this.config.clientSecret) {
                formData.append('client_secret', this.config.clientSecret);
            }

            const response = await fetch(refreshUrl, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded',
                },
                body: formData.toString()
            });

            if (!response.ok) {
                throw new Error('Token刷新失败');
            }

            const tokenData = await response.json();

            // 更新Token
            this.accessToken = tokenData.access_token;
            this.refreshToken = tokenData.refresh_token;

            // 重新加载用户信息（以防有变更）
            await this.loadUserProfile();

            // 更新存储
            this.saveToStorage();
            this.updateAxiosHeaders();

            // 重新设置刷新定时器
            this.setupTokenRefresh();

            // 处理等待队列
            this.refreshQueue.forEach(({ resolve }) => resolve(true));
            this.refreshQueue = [];

            this.emit('tokenRefreshed', {
                timestamp: new Date()
            });

            return true;
        } catch (error) {
            console.error('Token刷新失败:', error);

            // 处理等待队列中的错误
            this.refreshQueue.forEach(({ reject }) => reject(error));
            this.refreshQueue = [];

            // 刷新失败，清理会话
            await this.clearSession();

            this.emit('tokenRefreshFailed', {
                error: error.message,
                timestamp: new Date()
            });

            throw error;
        } finally {
            this.isRefreshing = false;
        }
    }

    /**
     * 验证Token有效性
     */
    async validateToken() {
        try {
            if (!this.accessToken) {
                return false;
            }

            if (this.isTokenExpired(this.accessToken)) {
                if (this.refreshToken) {
                    return await this.refreshAccessToken();
                }
                return false;
            }

            // 通过API验证Token
            const response = await axios.post('/api/user-system/auth/validate', {
                accessToken: this.accessToken
            });

            return response.data;
        } catch (error) {
            console.error('Token验证失败:', error);
            return false;
        }
    }

    /**
     * 检查用户权限
     */
    hasPermission(permission) {
        if (!this.permissions || this.permissions.length === 0) {
            return false;
        }

        return this.permissions.includes(permission) ||
               this.permissions.includes('*') || // 超级管理员权限
               this.permissions.includes(`${permission}.*`); // 通配符权限
    }

    /**
     * 检查用户角色
     */
    hasRole(role) {
        return this.roles && this.roles.includes(role);
    }

    /**
     * 设置axios拦截器
     */
    setupAxiosInterceptors() {
        // 请求拦截器
        axios.interceptors.request.use(
            (config) => {
                // 如果是认证相关的请求，跳过Token检查
                if (config.url.includes('/auth/')) {
                    return config;
                }

                // 添加认证头
                if (this.accessToken && !this.isTokenExpired(this.accessToken)) {
                    config.headers.Authorization = `Bearer ${this.accessToken}`;
                }

                return config;
            },
            (error) => {
                return Promise.reject(error);
            }
        );

        // 响应拦截器
        axios.interceptors.response.use(
            (response) => response,
            async (error) => {
                const originalRequest = error.config;

                // 如果是401错误且不是重试请求
                if (error.response?.status === 401 && !originalRequest._retry) {
                    originalRequest._retry = true;

                    try {
                        // 尝试刷新Token
                        await this.refreshAccessToken();

                        // 重新发送原请求
                        originalRequest.headers.Authorization = `Bearer ${this.accessToken}`;
                        return axios(originalRequest);
                    } catch (refreshError) {
                        // 刷新失败，清理会话并重定向到登录页
                        await this.clearSession();
                        this.emit('unauthorized');

                        // 跳转到登录页
                        if (typeof window !== 'undefined') {
                            window.location.href = '/login';
                        }
                    }
                }

                return Promise.reject(error);
            }
        );
    }

    /**
     * 从存储初始化
     */
    initFromStorage() {
        try {
            const storage = this.getStorage();
            const data = storage.getItem('matrix_auth_data');

            if (data) {
                const authData = JSON.parse(data);

                if (authData.accessToken && !this.isTokenExpired(authData.accessToken)) {
                    this.accessToken = authData.accessToken;
                    this.refreshToken = authData.refreshToken;
                    this.user = authData.user;
                    this.permissions = authData.permissions || [];
                    this.roles = authData.roles || [];
                    this.tenantInfo = authData.tenantInfo;

                    this.updateAxiosHeaders();

                    if (this.config.autoRefresh) {
                        this.setupTokenRefresh();
                    }
                } else {
                    this.clearSession();
                }
            }
        } catch (error) {
            console.error('从存储初始化认证数据失败:', error);
            this.clearSession();
        }
    }

    /**
     * 保存到存储
     */
    saveToStorage(rememberMe = false) {
        try {
            const storage = this.getStorage(rememberMe);

            storage.setItem('matrix_auth_data', JSON.stringify({
                accessToken: this.accessToken,
                refreshToken: this.refreshToken,
                user: this.user,
                permissions: this.permissions,
                roles: this.roles,
                tenantInfo: this.tenantInfo
            }));
        } catch (error) {
            console.error('保存认证数据失败:', error);
        }
    }

    /**
     * 清理会话
     */
    async clearSession() {
        this.accessToken = null;
        this.refreshToken = null;
        this.user = null;
        this.permissions = [];
        this.roles = [];
        this.tenantInfo = null;

        // 清理刷新定时器
        if (this.tokenRefreshTimer) {
            clearTimeout(this.tokenRefreshTimer);
            this.tokenRefreshTimer = null;
        }

        // 清理存储
        try {
            localStorage.removeItem('matrix_auth_data');
            sessionStorage.removeItem('matrix_auth_data');
        } catch (error) {
            console.error('清理认证数据失败:', error);
        }

        // 更新axios头部
        this.updateAxiosHeaders();
    }

    /**
     * 设置Token刷新定时器
     */
    setupTokenRefresh() {
        if (!this.accessToken || !this.config.autoRefresh) {
            return;
        }

        // 清理现有定时器
        if (this.tokenRefreshTimer) {
            clearTimeout(this.tokenRefreshTimer);
        }

        try {
            const decodedToken = this.decodeJWT(this.accessToken);
            const expiresAt = decodedToken.exp * 1000;
            const refreshAt = expiresAt - this.config.tokenRefreshThreshold;
            const delay = refreshAt - Date.now();

            if (delay > 0) {
                this.tokenRefreshTimer = setTimeout(async () => {
                    try {
                        await this.refreshAccessToken();
                    } catch (error) {
                        console.error('自动刷新Token失败:', error);
                    }
                }, delay);
            }
        } catch (error) {
            console.error('设置Token刷新定时器失败:', error);
        }
    }

    /**
     * 获取租户对应的Realm
     */
    getRealmForTenant(tenantId) {
        if (!tenantId || tenantId === '' || tenantId === 'default') {
            return this.config.defaultRealm;
        }

        return `tenant-${tenantId}`;
    }

    /**
     * 解码JWT Token
     */
    decodeJWT(token) {
        try {
            const payload = token.split('.')[1];
            const decoded = atob(payload.replace(/-/g, '+').replace(/_/g, '/'));
            return JSON.parse(decoded);
        } catch (error) {
            console.error('解码JWT失败:', error);
            return {};
        }
    }

    /**
     * 检查Token是否过期
     */
    isTokenExpired(token) {
        try {
            const decoded = this.decodeJWT(token);
            return decoded.exp * 1000 < Date.now();
        } catch (error) {
            return true;
        }
    }

    /**
     * 更新axios认证头
     */
    updateAxiosHeaders() {
        if (this.accessToken && !this.isTokenExpired(this.accessToken)) {
            axios.defaults.headers.common['Authorization'] = `Bearer ${this.accessToken}`;
        } else {
            delete axios.defaults.headers.common['Authorization'];
        }
    }

    /**
     * 获取认证头
     */
    getAuthHeaders() {
        if (this.accessToken && !this.isTokenExpired(this.accessToken)) {
            return {
                'Authorization': `Bearer ${this.accessToken}`
            };
        }
        return {};
    }

    /**
     * 获取存储对象
     */
    getStorage(rememberMe = false) {
        return rememberMe ? localStorage : sessionStorage;
    }

    /**
     * 获取错误消息
     */
    getErrorMessage(error) {
        if (typeof error === 'string') {
            return error;
        }

        if (error.response?.data?.message) {
            return error.response.data.message;
        }

        if (error.message) {
            return error.message;
        }

        return '未知错误';
    }

    /**
     * 验证并刷新Token
     */
    async validateAndRefreshToken() {
        try {
            const isValid = await this.validateToken();
            if (!isValid) {
                throw new Error('Token无效或已过期');
            }
        } catch (error) {
            await this.clearSession();
            throw error;
        }
    }

    // ==================== ABP集成方法 ====================

    /**
     * 与ABP会话信息同步
     */
    async syncWithAbpSession() {
        try {
            if (this.user) {
                // 同步用户信息到ABP
                const abpUserInfo = {
                    id: this.user.id,
                    userName: this.user.username,
                    name: this.user.name,
                    surname: this.user.surname,
                    email: this.user.email,
                    isActive: true,
                    tenantId: this.user.tenantId
                };

                abpService.setUser(abpUserInfo);
            }

            if (this.tenantInfo) {
                // 同步租户信息到ABP
                const abpTenantInfo = {
                    id: this.tenantInfo.id,
                    name: this.tenantInfo.name,
                    displayName: this.tenantInfo.displayName
                };

                abpService.setTenant(abpTenantInfo);
            }

            // 同步权限信息到ABP
            if (this.permissions && this.permissions.length > 0) {
                const grantedPolicies = {};
                this.permissions.forEach(permission => {
                    grantedPolicies[permission] = true;
                });
                Object.assign(abpService.auth.grantedPolicies, grantedPolicies);
            }

        } catch (error) {
            console.error('ABP会话同步失败:', error);
        }
    }

    /**
     * 检查ABP权限
     * @param {string} permissionName 权限名称
     * @returns {boolean} 是否有权限
     */
    hasAbpPermission(permissionName) {
        return abpService.hasPermission(permissionName);
    }

    /**
     * 检查ABP功能是否启用
     * @param {string} featureName 功能名称
     * @returns {boolean} 功能是否启用
     */
    isAbpFeatureEnabled(featureName) {
        return abpService.isFeatureEnabled(featureName);
    }

    /**
     * 获取ABP功能值
     * @param {string} featureName 功能名称
     * @returns {any} 功能值
     */
    getAbpFeatureValue(featureName) {
        return abpService.getFeatureValue(featureName);
    }

    /**
     * 获取ABP设置值
     * @param {string} settingName 设置名称
     * @returns {string} 设置值
     */
    getAbpSetting(settingName) {
        return abpService.getSetting(settingName);
    }

    /**
     * 获取本地化文本
     * @param {string} key 文本键
     * @param {string} resourceName 资源名称
     * @returns {string} 本地化文本
     */
    localize(key, resourceName) {
        return abpService.localize(key, resourceName);
    }

    /**
     * 切换ABP语言
     * @param {string} cultureName 语言代码
     */
    async changeAbpLanguage(cultureName) {
        try {
            await abpService.changeLanguage(cultureName);

            // 更新本地配置
            this.config.defaultLanguage = cultureName;
            this.saveToStorage();

            this.emit('languageChanged', cultureName);
        } catch (error) {
            console.error('切换语言失败:', error);
            throw error;
        }
    }

    /**
     * 解析ABP租户
     * @param {string} tenantName 租户名称
     * @returns {Object} 租户解析结果
     */
    async resolveAbpTenant(tenantName) {
        try {
            const result = await abpService.resolveTenant(tenantName);

            if (result.tenantId) {
                this.tenantInfo = {
                    id: result.tenantId,
                    name: tenantName,
                    displayName: tenantName,
                    realm: `tenant-${result.tenantId}`
                };

                abpService.setTenant(this.tenantInfo);
            }

            return result;
        } catch (error) {
            console.error('解析租户失败:', error);
            throw error;
        }
    }

    /**
     * 刷新ABP权限信息
     */
    async refreshAbpPermissions() {
        try {
            // 重新加载ABP权限
            await abpService.loadPermissions();

            // 同步到本地权限
            this.permissions = Object.keys(abpService.auth.grantedPolicies);

            // 保存到本地存储
            this.saveToStorage();

            this.emit('permissionsRefreshed', this.permissions);
        } catch (error) {
            console.error('刷新权限失败:', error);
            throw error;
        }
    }

    /**
     * 刷新ABP功能设置
     */
    async refreshAbpFeatures() {
        try {
            await abpService.loadFeatures();

            this.emit('featuresRefreshed', abpService.features.values);
        } catch (error) {
            console.error('刷新功能设置失败:', error);
            throw error;
        }
    }

    /**
     * 刷新ABP用户设置
     */
    async refreshAbpSettings() {
        try {
            await abpService.loadSettings();

            this.emit('settingsRefreshed', abpService.settings.values);
        } catch (error) {
            console.error('刷新用户设置失败:', error);
            throw error;
        }
    }

    /**
     * 记录ABP日志
     * @param {string} level 日志级别
     * @param {string} message 日志消息
     * @param {Object} properties 附加属性
     */
    logAbpEvent(level, message, properties = {}) {
        const logInfo = {
            level,
            message,
            time: new Date(),
            properties
        };

        abpService.log(logInfo);
    }

    /**
     * 处理ABP通知
     * @param {Object} notification 通知信息
     */
    handleAbpNotification(notification) {
        abpService.handleNotification(notification);
        this.emit('abpNotification', notification);
    }

    /**
     * 重置ABP和认证服务
     */
    async reset() {
        try {
            // 重置ABP服务
            abpService.reset();

            // 重置认证服务
            await this.clearSession();

            this.emit('reset');
        } catch (error) {
            console.error('重置服务失败:', error);
            throw error;
        }
    }

    /**
     * 增强的Token验证 - 集成ABP验证
     */
    async validateTokenEnhanced() {
        try {
            // 原有Token验证
            const isValid = await this.validateToken();

            if (!isValid) {
                return false;
            }

            // ABP会话验证
            if (abpService.isInitialized.value) {
                // 验证ABP会话状态
                if (!abpService.session.user) {
                    await this.syncWithAbpSession();
                }
            }

            return true;
        } catch (error) {
            console.error('增强Token验证失败:', error);
            return false;
        }
    }

    /**
     * 获取完整的权限信息（合并本地和ABP权限）
     * @returns {Array} 权限列表
     */
    getAllPermissions() {
        const localPermissions = this.permissions || [];
        const abpPermissions = Object.keys(abpService.auth.grantedPolicies);

        // 合并权限并去重
        const allPermissions = [...new Set([...localPermissions, ...abpPermissions])];

        return allPermissions;
    }

    /**
     * 获取用户角色信息（集成ABP角色）
     * @returns {Array} 角色列表
     */
    getAllRoles() {
        const localRoles = this.roles || [];
        const abpUser = abpService.session.user;
        const abpRoles = abpUser?.roles || [];

        // 合并角色并去重
        const allRoles = [...new Set([...localRoles, ...abpRoles])];

        return allRoles;
    }
}

// 创建单例实例
const authService = new AuthService();

export default authService;
export { AuthService };